//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_8042_H__
#define __ELASTOS_8042_H__

enum {
    KeyboardPort_InputRegister      = 0x60,         // Write
    KeyboardPort_OutputRegister     = 0x60,         // Read
    KeyboardPort_StatusRegister     = 0x64,         // Read
    KeyboardPort_ControlRegister    = 0x64,         // Write
};

// Status Register
enum {
    SR_OutputBufferFull             = __8BIT(0),
    SR_InputBufferFull              = __8BIT(1),
    SR_SystemFlag                   = __8BIT(2),    // set to 0 after power
                                                    //  on reset
    SR_Command                      = __8BIT(3),    // data in input register is
                                                    //  command (1) or data (0)
    SR_KeyboardEnable               = __8BIT(4),    // 1 = keyboard enabled,
                                                    // 0 = keyboard disabled
    SR_TransmitTimeout              = __8BIT(5),
    SR_ReceiveTimeout               = __8BIT(6),
    SR_EvenParity                   = __8BIT(7),    // 1 = even parity rec'd
                                                    // 0 = odd  parity rec'd
};

// 8042 output port
enum {
    OutputPort_SystemReset          = __8BIT(0),    // 1: Normal
                                                    // 0: Reset computer
    OutputPort_A20Gate              = __8BIT(1),    // 1: Enable
                                                    // 0: Disable
};

// 8042 command
enum {
    Command_ReadOutputPort          = 0xd0,
    Command_WriteOutputPort         = 0xd1,

    Command_SetOutputPortLowNibble  = 0xf0,  // The official explanation says
                                             // that it keeps the corresponding
                                             // bits in the output port low
                                             // for 6ms...

    Command_SystemReset             =
        (Command_SetOutputPortLowNibble | LONIBBLE(~OutputPort_SystemReset)),
};

INLINE void WaitInputBufferEmpty()
{
    while (Inb(KeyboardPort_StatusRegister) & SR_InputBufferFull);
}

INLINE void WriteOutputPort(uint8_t u8Data)
{
    WaitInputBufferEmpty();

    Outb(KeyboardPort_ControlRegister, Command_WriteOutputPort);

    WaitInputBufferEmpty();

    Outb(KeyboardPort_OutputRegister, u8Data);
}

INLINE void SystemReset()
{
    WaitInputBufferEmpty();

    Outb(KeyboardPort_ControlRegister, Command_SystemReset);
}

#endif // __ELASTOS_8042_H__
